#pragma once

#include <stdio.h>

namespace abstract_factory {
    
/// @brief 抽象产品 - 定义了产品的规范，描述了产品的主要特性和功能
class AbstractProductA {
public:
    virtual ~AbstractProductA() {}
    virtual void Show() = 0;
};
class AbstractProductB {
public:
    virtual ~AbstractProductB() {}
    virtual void Show() = 0;
};

/// @brief 具体产品 - 实现了抽象产品角色所定义的接口，由具体工厂来创建，它同具体工厂之间一一对应
class ConcreteProductA1 : public AbstractProductA {
public:
    virtual void Show() {
        printf("ConcreteProductA1 Show ...\n");
    }
};
class ConcreteProductA2 : public AbstractProductA {
public:
    virtual void Show() {
        printf("ConcreteProductA2 Show ...\n");
    }
};
class ConcreteProductB1 : public AbstractProductB {
public:
    virtual void Show() {
        printf("ConcreteProductB1 Show ...\n");
    }
};
class ConcreteProductB2 : public AbstractProductB {
public:
    virtual void Show() {
        printf("ConcreteProductB2 Show ...\n");
    }
};

/// @brief 抽象工厂 - 提供了创建产品的接口
class AbstractFactory {
public:
    virtual ~AbstractFactory() {}
    virtual AbstractProductA* CreateProductA() = 0;
    virtual AbstractProductB* CreateProductB() = 0;
};

/// @brief 具体工厂 - 实现抽象工厂中的抽象方法，完成具体产品的创建
class ConcreteFactory1 : public AbstractFactory {
public:
    virtual AbstractProductA* CreateProductA() {
        AbstractProductA* ptr = new ConcreteProductA1();
        return ptr;
    }
    virtual AbstractProductB* CreateProductB() {
        AbstractProductB* ptr = new ConcreteProductB1();
        return ptr;
    }
};
class ConcreteFactory2 : public AbstractFactory {
public:
    virtual AbstractProductA* CreateProductA() {
        AbstractProductA* ptr = new ConcreteProductA2();
        return ptr;
    }
    virtual AbstractProductB* CreateProductB() {
        AbstractProductB* ptr = new ConcreteProductB2();
        return ptr;
    }
};

} // namespace abstract_factory

void Test_04_abstract_factory_impl_1() {
    printf("-------------------- %s --------------------\n", __FUNCTION__);
    abstract_factory::AbstractFactory* ptr_factory_1 = new abstract_factory::ConcreteFactory1();
    abstract_factory::AbstractProductA* ptr_product_A1 = ptr_factory_1->CreateProductA();
    ptr_product_A1->Show();
    delete ptr_factory_1;
    delete ptr_product_A1;
}

// -------------------- Test_04_abstract_factory_impl_1 --------------------
// ConcreteProductA1 Show ...